package com.lyncs.ods.modules.txn.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.lyncs.ods.common.api.CommonPage;
import com.lyncs.ods.common.exception.ApiException;
import com.lyncs.ods.common.web.RequestHolder;
import com.lyncs.ods.constant.LyncsOdsConstant;
import com.lyncs.ods.constant.TagInfoEnum;
import com.lyncs.ods.modules.company.model.CompanyInfo;
import com.lyncs.ods.modules.company.service.CompanyInfoService;
import com.lyncs.ods.modules.company.service.CompanyUserRoleService;
import com.lyncs.ods.modules.goods.model.SkuDetail;
import com.lyncs.ods.modules.goods.model.SkuInfo;
import com.lyncs.ods.modules.goods.service.SkuDetailService;
import com.lyncs.ods.modules.goods.service.SkuInfoService;
import com.lyncs.ods.modules.msg.service.MessageService;
import com.lyncs.ods.modules.txn.model.*;
import com.lyncs.ods.modules.txn.service.*;
import com.lyncs.ods.modules.user.service.CompanyUserRelationService;
import com.lyncs.ods.req.ListPageSearchReq;
import com.lyncs.ods.req.SaveDeliverReq;
import com.lyncs.ods.resp.*;
import com.lyncs.ods.utils.PageUtil;
import com.lyncs.ods.utils.ParamCheckUtil;
import com.lyncs.ods.utils.TxnCommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author alex
 * @date 2022/2/26 18:46
 * @description
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class DeliverServiceImpl implements DeliverService {

    @Autowired
    private DeliverInfoServiceImpl deliverInfoService;
    @Autowired
    private TxnSkuDetailService txnSkuDetailService;
    @Autowired
    private SkuInfoService skuInfoService;
    @Autowired
    private CompanyInfoService companyInfoService;
    @Autowired
    private CompanyUserRelationService companyUserRelationService;
    @Autowired
    private SkuDetailService skuDetailService;
    @Autowired
    private TxnOperateInfoService txnOperateInfoService;
    @Autowired
    private TxnEditLogService txnEditLogService;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private DeliverBillInfoService deliverBillInfoService;
    @Autowired
    private TxnFeeDetailService txnFeeDetailService;
    @Autowired
    private SettlementBillInfoService settlementBillInfoService;
    @Autowired
    private SettlementInfoService settlementInfoService;
    @Autowired
    private MessageService messageService;
    @Autowired
    private CompanyUserRoleService companyUserRoleService;

    @Override
    public Long saveDeliver(SaveDeliverReq req) {
        ParamCheckUtil.checkTxnOptions(req);
        LocalDate dbDate = null;
        String dbName = null;
        DeliverInfo dbDeliver = null;
        DeliverInfo deliverInfo = new DeliverInfo();
        if (req.getDeliverId() == null) {
            //insert
            deliverInfo = new DeliverInfo().setId(IdUtil.getSnowflakeNextId())
                    .setSellerId(req.getSellerId())
                    .setBuyerId(req.getBuyerId())
                    .setCurrency(req.getCurrency())
                    .setCreateTime(RequestHolder.getRequestDateTime())
                    .setCreator(RequestHolder.getUserId())
                    .setStatus(LyncsOdsConstant.DeliverStatus.INIT.getKey())
                    .setCreatorCompanyId(RequestHolder.getCompanyId());
        } else {
            //update
            dbDeliver = deliverInfoService.getOneById(req.getDeliverId());
            BeanUtils.copyProperties(dbDeliver, deliverInfo);
            dbName = dbDeliver.getDeliverName();
            dbDate = dbDeliver.getStartDate();
        }

        if (req.getOperateType() == 1) {
            deliverInfo.setStatus(LyncsOdsConstant.DeliverStatus.DRAFT.getKey());
        } else if (LyncsOdsConstant.OrderStatus.DRAFT.getKey().equals(deliverInfo.getStatus())) {
            deliverInfo.setStatus(LyncsOdsConstant.OrderStatus.INIT.getKey());
        }
        Function<List<DeliverInfo>, Map<Long, CompanyShortInfoResp>> companyInfoFunc = (list) -> companyInfoService.getTxnCompanyRespInfos(list);
        String deliverName = TxnCommonUtils.buildTicketName(
                deliverInfoService.lambdaQuery().setEntityClass(DeliverInfo.class).ne(DeliverInfo::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey()),
                companyInfoFunc, LyncsOdsConstant.TxnType.DELIVER, deliverInfo,
                req.getStartDate(), dbDate, req.getDeliverName(), dbName);
        deliverInfo.setCategoryCount(req.getSkuInfoList().size())
                .setTotalAmount(calculateDeliverAmount(req))
                .setRemark(req.getRemark())
                .setLastUpdater(RequestHolder.getUserId())
                .setUpdateTime(RequestHolder.getRequestDateTime())
                .setStartDate(req.getStartDate())
                .setDeliverName(deliverName)
                .setLocation(req.getLocation())
                .setFlightNumber(req.getFlightNumber())
                .setDeparture(req.getDeparture())
                .setDestination(req.getDestination())
                .setCustomFields(req.getCustomFields())
                .setAttachment(req.getAttachment());

        Long logId = IdUtil.getSnowflakeNextId();
        saveSkuInfo(req, deliverInfo, logId);
        saveBillInfo(req, deliverInfo, logId);

        deliverInfoService.saveOrUpdate(deliverInfo);
        handleSettlementInfo(deliverInfo);
        if (req.getOperateType() != 1 && req.getDeliverId() != null) {
            deliverInfoService.updateDeliveryStatus(List.of(req.getDeliverId()));
        }
        saveLog(dbDeliver, deliverInfo, logId);
        DeliverInfo finalDeliverInfo = deliverInfo;
        BiConsumer<CompanyInfo, CompanyInfo> emailNotifyFunc = (companyInfo, invitedCompanyInfo) -> messageService.shareTicketByEmail(req.getDeliverId() == null, LyncsOdsConstant.TxnType.DELIVER, finalDeliverInfo.getId(), companyInfo, invitedCompanyInfo, companyInfoService.getNotifyEmail(finalDeliverInfo));
        BiConsumer<CompanyInfo, CompanyInfo> smsNotifyFunc = (companyInfo, invitedCompanyInfo) -> messageService.shareTicketBySms(req.getDeliverId() == null, LyncsOdsConstant.TxnType.DELIVER, finalDeliverInfo.getId(), companyInfo, invitedCompanyInfo.getId(), companyInfoService.getNotifyPhone(finalDeliverInfo));
        Function<List<Long>, Map<Long, CompanyInfo>> companyFunc = (list) -> companyInfoService.getAvailableCompanyInfos(list).stream().collect(Collectors.toMap(CompanyInfo::getId, o -> o));
        TxnCommonUtils.notify(deliverInfo, companyFunc, emailNotifyFunc, smsNotifyFunc);
        return finalDeliverInfo.getId();
    }

    public void saveLog(DeliverInfo oldInfo, DeliverInfo newInfo, Long logId) {
        txnEditLogService.saveLog(oldInfo, newInfo, LyncsOdsConstant.TxnType.DELIVER, newInfo.getId(), logId, companyInfoService::getLoginCompanyName, companyUserRelationService::getLoginUserName);
    }

    private BigDecimal calculateDeliverAmount(SaveDeliverReq req) {
        //货款
        /*BigDecimal otherAmount = BigDecimal.ZERO;
        if (CollectionUtils.isNotEmpty(req.getBillInfos())) {
            otherAmount = req.getBillInfos().stream().flatMap(bill -> bill.getFeeInfoList().stream())
                    .map(SaveDeliverReq.DeliverFeeInfo::getFeeAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }*/
        return req.getBillInfos().stream().flatMap(bill -> bill.getFeeInfos().stream())
                .map(SaveDeliverReq.DeliverFeeInfo::getFeeAmount)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 保存 交付单sku信息
     *
     * @param req   request
     * @param logId logId
     */
    private void saveSkuInfo(SaveDeliverReq req, DeliverInfo deliverInfo, Long logId) {
        //交付单关联的sku
        List<TxnSkuDetail> deliverSkuDetails = new ArrayList<>();
        if (Objects.nonNull(req.getDeliverId())) {
            deliverSkuDetails = txnSkuDetailService.getTxnSkuDetail(null, req.getDeliverId());
        }
        List<Triple<Long, Long, BigDecimal>> orderSkuCountList = new ArrayList<>();
        Triple<List<TxnSkuDetail>, List<Long>, List<Pair<TxnSkuDetail, TxnSkuDetail>>> deliverDiffSkus = TxnCommonUtils.getDeliverDiffSkus(deliverInfo.getId(), req.getSkuInfoList(), deliverSkuDetails, orderSkuCountList);

        List<TxnSkuDetail> newDeliverSkus = deliverDiffSkus.getLeft();
        List<Long> delSkuIds = deliverDiffSkus.getMiddle();
        List<Pair<TxnSkuDetail, TxnSkuDetail>> updateDeliverSkus = deliverDiffSkus.getRight();
        if (CollectionUtil.isNotEmpty(newDeliverSkus)) {
            txnSkuDetailService.saveBatch(newDeliverSkus);
        }
        if (CollectionUtil.isNotEmpty(delSkuIds)) {
            txnSkuDetailService.lambdaUpdate()
                    .eq(TxnSkuDetail::getDeliverId, deliverInfo.getId())
                    .in(TxnSkuDetail::getSkuId, delSkuIds)
                    .set(TxnSkuDetail::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey())
                    .update();
        }
        if (CollectionUtil.isNotEmpty(updateDeliverSkus)) {
            txnSkuDetailService.updateBatchById(updateDeliverSkus.stream().map(Pair::getRight).collect(Collectors.toList()));
        }
        if (req.getOperateType() != 1) {
            saveOrderSkuInfo(deliverInfo, orderSkuCountList);
        }
        saveSkuLog(newDeliverSkus, delSkuIds, updateDeliverSkus, deliverInfo.getId(), logId, req.getDeliverId() == null);
    }

    public void saveSkuLog(List<TxnSkuDetail> insertSubItems, List<Long> deleteSubItems, List<Pair<TxnSkuDetail, TxnSkuDetail>> updateSubItems, Long orderId, Long logId, boolean isNew) {
        LyncsOdsConstant.TxnEditType type = isNew ? LyncsOdsConstant.TxnEditType.ADD : LyncsOdsConstant.TxnEditType.EDIT;
        List<Long> skuIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(insertSubItems)) {
            skuIds.addAll(insertSubItems.stream().map(TxnSkuDetail::getSkuId).distinct().collect(Collectors.toList()));
        }
        if (CollectionUtil.isNotEmpty(updateSubItems)) {
            skuIds.addAll(updateSubItems.stream().map(Pair::getRight).map(TxnSkuDetail::getSkuId).distinct().collect(Collectors.toList()));
        }
        if (CollectionUtil.isNotEmpty(deleteSubItems)) {
            skuIds.addAll(deleteSubItems);
        }
        List<SkuInfo> skuInfos = skuInfoService.lambdaQuery().in(SkuInfo::getId, skuIds).list();
        Map<Long, String> skuNameMap = skuInfos.stream().collect(Collectors.toMap(SkuInfo::getId, SkuInfo::getName));
        txnEditLogService.saveSubItemLog(insertSubItems, deleteSubItems, updateSubItems, LyncsOdsConstant.TxnType.DELIVER, type, LyncsOdsConstant.TxnType.SKU, orderId, logId, companyInfoService::getLoginCompanyName, companyUserRelationService::getLoginUserName, skuNameMap);
    }

    /**
     * 更改交付单关联订单sku状态
     *
     * @param deliverInfo       deliverInfo
     * @param orderSkuCountList orderSkuCountList
     */
    private void saveOrderSkuInfo(DeliverInfo deliverInfo, List<Triple<Long, Long, BigDecimal>> orderSkuCountList) {
        if (CollectionUtil.isEmpty(orderSkuCountList) || LyncsOdsConstant.DeliverStatus.DRAFT.getKey().equals(deliverInfo.getStatus())) {
            return;
        }
        //修改订单已交付量
        List<TxnSkuDetail> orderSkuDetails = txnSkuDetailService.lambdaQuery()
                .isNull(TxnSkuDetail::getDeliverId)
                .ne(TxnSkuDetail::getStatus, LyncsOdsConstant.TxnSkuStatus.DELETED.getKey())
                .and(andWrapper -> orderSkuCountList.forEach(triple -> andWrapper.or(orWrapper -> orWrapper.eq(TxnSkuDetail::getOrderId, triple.getLeft()).eq(TxnSkuDetail::getSkuId, triple.getMiddle()))))
                .list();
        Map<String, BigDecimal> orderSkuMap = orderSkuCountList.stream().collect(Collectors.toMap(triple -> StringUtils.join(triple.getLeft(), LyncsOdsConstant.Common.WELL, triple.getMiddle()), Triple::getRight));
        List<TxnSkuDetail> updateList = orderSkuDetails.stream().map(sku -> {
            BigDecimal bigDecimal = orderSkuMap.getOrDefault(StringUtils.join(sku.getOrderId(), LyncsOdsConstant.Common.WELL, sku.getSkuId()), null);
            if (Objects.isNull(bigDecimal)) {
                return null;
            }
            BigDecimal deliveredCount = sku.getDeliveredCount().add(bigDecimal);
            if (deliveredCount.compareTo(sku.getTotalCount()) > 0) {
                throw new ApiException("请勿超量交付，" + sku.getOrderId() + "@" + sku.getSkuId() + "的待交付量为" + (sku.getTotalCount().subtract(sku.getDeliveredCount())) + "，小于当前填写交付量：" + bigDecimal);
            }
            Integer status = deliveredCount.compareTo(BigDecimal.ZERO) == 0 ? LyncsOdsConstant.TxnSkuStatus.INIT.getKey() : deliveredCount.compareTo(sku.getTotalCount()) < 0 ? LyncsOdsConstant.TxnSkuStatus.PARTIAL_DELIVERY.getKey() : LyncsOdsConstant.TxnSkuStatus.DELIVERED.getKey();
            return new TxnSkuDetail().setId(sku.getId())
                    .setOrderId(sku.getOrderId())
                    .setDeliveredCount(deliveredCount)
                    .setStatus(status)
                    .setLastUpdater(RequestHolder.getUserId())
                    .setUpdateTime(RequestHolder.getRequestDateTime());
        }).filter(Objects::nonNull).collect(Collectors.toList());
        txnSkuDetailService.updateBatchById(updateList);

        orderInfoService.updateOrderStatus(updateList.stream().map(TxnSkuDetail::getOrderId).distinct().collect(Collectors.toList()));
    }

    /**
     * 保存 交付单账款信息
     *
     * @param req request
     */
    private void saveBillInfo(SaveDeliverReq req, DeliverInfo deliverInfo, Long logId) {
        LyncsOdsConstant.TxnEditType type = req.getDeliverId() == null ? LyncsOdsConstant.TxnEditType.ADD : LyncsOdsConstant.TxnEditType.EDIT;
        List<TxnFeeDetail> feeDetails = new ArrayList<>();
        List<DeliverBillInfo> billInfos = new ArrayList<>();
        if (req.getDeliverId() != null) {
            billInfos = deliverBillInfoService.lambdaQuery()
                    .eq(DeliverBillInfo::getDeliverId, deliverInfo.getId())
                    .ne(DeliverBillInfo::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey())
                    .list();
            List<Long> billIds = billInfos.stream().map(DeliverBillInfo::getId).collect(Collectors.toList());
            feeDetails = txnFeeDetailService.lambdaQuery().in(TxnFeeDetail::getBillId, billIds).eq(TxnFeeDetail::getStatus, LyncsOdsConstant.EnableStatus.ENABLE.getKey()).list();
        }
        Triple<Map<DeliverBillInfo, List<TxnFeeDetail>>, Map<Long, List<TxnFeeDetail>>, Map<DeliverBillInfo, Triple<List<TxnFeeDetail>, List<TxnFeeDetail>, List<Pair<TxnFeeDetail, TxnFeeDetail>>>>> deliverBiiFeeDiff = TxnCommonUtils.getDeliverBillFeeDiff(deliverInfo.getId(), req.getCurrency(), req.getBillInfos(), billInfos, feeDetails);
        //insert
        Map<DeliverBillInfo, List<TxnFeeDetail>> insertBillFeeMap = deliverBiiFeeDiff.getLeft();
        //delete
        Map<Long, List<TxnFeeDetail>> deleteBillFeeMap = deliverBiiFeeDiff.getMiddle();
        //update
        Map<DeliverBillInfo, Triple<List<TxnFeeDetail>, List<TxnFeeDetail>, List<Pair<TxnFeeDetail, TxnFeeDetail>>>> updateBillFeeMap = deliverBiiFeeDiff.getRight();
        List<TxnFeeDetail> insertFees = new ArrayList<>();
        List<TxnFeeDetail> delFees = new ArrayList<>();
        List<Pair<TxnFeeDetail, TxnFeeDetail>> updateFees = new ArrayList<>();
        if (MapUtils.isNotEmpty(insertBillFeeMap)) {
            deliverBillInfoService.saveBatch(insertBillFeeMap.keySet());
            ArrayList<TxnFeeDetail> newBillFees = insertBillFeeMap.values().stream().collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);
            insertFees.addAll(newBillFees);
        }
        if (MapUtils.isNotEmpty(deleteBillFeeMap)) {
            deliverBillInfoService.lambdaUpdate()
                    .set(DeliverBillInfo::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey())
                    .in(DeliverBillInfo::getId, deleteBillFeeMap.keySet()).update();
            List<TxnFeeDetail> delBillFees = deleteBillFeeMap.values().stream().collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);
            delFees.addAll(delBillFees);
            handleDeliverBillDelete(deliverInfo.getId(), deleteBillFeeMap.keySet());
        }
        if (MapUtils.isNotEmpty(updateBillFeeMap)) {
            deliverBillInfoService.updateBatchById(updateBillFeeMap.keySet());
            updateBillFeeMap.values().forEach(triple -> {
                insertFees.addAll(triple.getLeft());
                delFees.addAll(triple.getMiddle());
                updateFees.addAll(triple.getRight());
            });
        }
        List<TxnFeeDetail> all = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(insertFees)) {
            txnFeeDetailService.saveBatch(insertFees);
            all.addAll(insertFees);
        }

        if (CollectionUtils.isNotEmpty(delFees)) {
            List<Long> feeIds = delFees.stream().map(TxnFeeDetail::getId).collect(Collectors.toList());
            txnFeeDetailService.lambdaUpdate().set(TxnFeeDetail::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey())
                    .in(TxnFeeDetail::getId, feeIds)
                    .update();
            all.addAll(delFees);
        }
        if (CollectionUtils.isNotEmpty(updateFees)) {
            List<TxnFeeDetail> updateFeeDetails = updateFees.stream().map(Pair::getRight).collect(Collectors.toList());
            txnFeeDetailService.updateBatchById(updateFeeDetails);
            all.addAll(updateFeeDetails);
        }
        List<Long> delFeeIds = delFees.stream().map(TxnFeeDetail::getId).collect(Collectors.toList());
        Map<Long, String> feeNameMap = all.stream().collect(Collectors.toMap(TxnFeeDetail::getId, TxnFeeDetail::getFeeName));
        txnEditLogService.saveSubItemLog(insertFees, delFeeIds, updateFees, LyncsOdsConstant.TxnType.DELIVER, type, LyncsOdsConstant.TxnType.FEE, deliverInfo.getId(), logId, companyInfoService::getLoginCompanyName, companyUserRelationService::getLoginUserName, feeNameMap);
    }

    @Override
    public CommonPage<ListPageResp> listDeliver(ListPageSearchReq req) {
        List<Long> topIdList = txnOperateInfoService.getTopTicket(RequestHolder.getCompanyId(), LyncsOdsConstant.TxnType.DELIVER.getKey());
        BiFunction<Long, Long, List<Long>> partnerFunc = (userId, companyId) -> companyUserRoleService.listAllAvailablePartnerId(userId, companyId);
        LambdaQueryChainWrapper<DeliverInfo> lambdaQueryChainWrapper = TxnCommonUtils.buildLambdaQueryWrapper(deliverInfoService.lambdaQuery().setEntityClass(DeliverInfo.class).ne(DeliverInfo::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey()), req, partnerFunc);
        Function<List<DeliverInfo>, Map<String, String>> staffNameFunc = (list) -> companyUserRelationService.getCompanyUserName(list);
        Function<List<DeliverInfo>, Map<Long, CompanyShortInfoResp>> companyInfoFunc = (list) -> companyInfoService.getTxnCompanyRespInfos(list);
        Function<List<Long>, List<TxnSkuDetailVO>> skuDetailFunc = (deliverIds) -> txnSkuDetailService.getDetails(null, deliverIds);
        return TxnCommonUtils.getListPageRespData(req, lambdaQueryChainWrapper, topIdList, skuDetailFunc, staffNameFunc, companyInfoFunc);
    }

    @Override
    public DeliverDetailInfoResp getDeliverDetail(Long deliverId) {
        DeliverInfo deliverInfo = deliverInfoService.getById(deliverId);
        if (Objects.isNull(deliverInfo)) {
            throw new ApiException("can not get deliver info for not exist or disabled.");
        }

        List<DeliverBillInfo> billInfos = deliverBillInfoService.lambdaQuery()
                .eq(DeliverBillInfo::getDeliverId, deliverInfo.getId())
                .ne(DeliverBillInfo::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey())
                .list();
        List<Long> billIds = billInfos.stream().map(DeliverBillInfo::getId).collect(Collectors.toList());
        List<TxnFeeDetail> txnFeeDetails = txnFeeDetailService.lambdaQuery().in(TxnFeeDetail::getBillId, billIds).eq(TxnFeeDetail::getStatus, LyncsOdsConstant.EnableStatus.ENABLE.getKey()).list();
        Map<Long, List<TxnFeeDetail>> billFeeDetailMap = txnFeeDetails.stream().collect(Collectors.groupingBy(TxnFeeDetail::getBillId));

        List<TxnSkuDetail> txnSkuDetails = txnSkuDetailService.getTxnSkuDetail(null, deliverId);
        Set<Long> skuIds = txnSkuDetails.stream().map(TxnSkuDetail::getSkuId).collect(Collectors.toSet());
        List<SkuInfo> skuInfos = skuInfoService.lambdaQuery().in(SkuInfo::getId, skuIds).list();
        Map<Long, SkuInfo> skuInfoMap = skuInfos.stream().collect(Collectors.toMap(SkuInfo::getId, o -> o));
        List<SkuDetail> skuDetails = skuDetailService.lambdaQuery().in(SkuDetail::getSkuId, skuIds).list();
        Map<Long, Map<String, String>> skuAttrMap = skuInfoService.getSkuAttrs(skuDetails);

        Map<Long, CompanyShortInfoResp> txnCompanyInfoMap = TxnCommonUtils.buildTxnCompanyInfo((list) -> companyInfoService.getTxnCompanyRespInfos(list), deliverInfo);
        Map<Integer, Integer> settleCategoryMap = new HashMap<>() {{
            put(LyncsOdsConstant.DeliverStatus.INIT.getKey(), 0);
            put(LyncsOdsConstant.DeliverStatus.PARTIAL_SETTLEMENT.getKey(), 0);
            put(LyncsOdsConstant.DeliverStatus.SETTLED.getKey(), 0);
        }};
        billInfos.forEach(bill -> {
            Integer cnt = settleCategoryMap.get(bill.getStatus());
            settleCategoryMap.put(bill.getStatus(), ++cnt);
        });
        Long orderCount = txnSkuDetails.stream().map(TxnSkuDetail::getOrderId).filter(Objects::nonNull).distinct().count();
        DeliverDetailInfoResp resp = new DeliverDetailInfoResp(deliverInfo);
        resp.setRelatedOrderCount(orderCount)
                .setSellerCompanyInfo(txnCompanyInfoMap.get(deliverInfo.getSellerId()))
                .setBuyerCompanyInfo(txnCompanyInfoMap.get(deliverInfo.getBuyerId()))
                .setCreatorName(companyUserRelationService.getCompanyUserName(deliverInfo))
                .setTotalSettledCount(settlementBillInfoService.getDeliverSettleCount(deliverId))
                .setTotalAmount(txnFeeDetails.stream().map(TxnFeeDetail::getFeeAmount).reduce(BigDecimal.ZERO, BigDecimal::add).toPlainString())
                .setPartialCount(settleCategoryMap.get(LyncsOdsConstant.DeliverStatus.PARTIAL_SETTLEMENT.getKey()))
                .setSettledCount(settleCategoryMap.get(LyncsOdsConstant.DeliverStatus.SETTLED.getKey()))
                .setUnsettledCount(settleCategoryMap.get(LyncsOdsConstant.DeliverStatus.INIT.getKey()))
                .setTop(txnOperateInfoService.isTopTicket(RequestHolder.getCompanyIdAllowNull(), LyncsOdsConstant.TxnType.DELIVER.getKey(), deliverId));
        Map<Long, String> orderNameMap = new HashMap<>();
        List<Long> orderIds = txnSkuDetails.stream().map(TxnSkuDetail::getOrderId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(orderIds)) {
            List<OrderInfo> orderInfos = orderInfoService.listByIds(orderIds);
            orderNameMap = orderInfos.stream().collect(Collectors.toMap(OrderInfo::getId, OrderInfo::getOrderName));
        }
        List<DeliverDetailInfoResp.SkuInfo> delSkus = new ArrayList<>();
        for (TxnSkuDetail txnSkuDetail : txnSkuDetails) {
            SkuInfo thisSkuInfo = skuInfoMap.get(txnSkuDetail.getSkuId());
            DeliverDetailInfoResp.SkuInfo skuInfo = new DeliverDetailInfoResp.SkuInfo()
                    .setOrderId(txnSkuDetail.getOrderId())
                    .setSkuId(txnSkuDetail.getSkuId())
                    .setOrderName(orderNameMap.get(txnSkuDetail.getOrderId()))
                    .setInnerCode(thisSkuInfo.getNo())
                    .setName(thisSkuInfo.getName())
                    .setImgUrl(thisSkuInfo.getImgUrl())
                    .setTotalCount(txnSkuDetail.getTotalCount())
                    .setDeliveredCount(txnSkuDetail.getDeliveredCount())
                    //.setUndeliveredCount(txnSkuDetail.getTotalCount().subtract(txnSkuDetail.getDeliveredCount()))
                    .setTotalAmount(txnSkuDetail.getTotalAmount().toPlainString())
                    .setAmount(txnSkuDetail.getAmount().toPlainString())
                    .setUnit(thisSkuInfo.getUnit())
                    .setTagInfos(JSONArray.parseArray(txnSkuDetail.getTagInfo(), TagInfo.class))
                    .setSkuAttrs(skuAttrMap.get(txnSkuDetail.getSkuId()))
                    .setRemark(txnSkuDetail.getRemark());
            delSkus.add(skuInfo);
        }
        List<DeliverDetailInfoResp.DeliverBillInfo> deliverBillInfos = billInfos.stream().map(bill -> {
            BigDecimal unsettledAmount = bill.getTotalAmount().subtract(bill.getSettledAmount());
            DeliverDetailInfoResp.DeliverBillInfo deliverBillInfo = new DeliverDetailInfoResp.DeliverBillInfo();
            List<TxnFeeDetail> feeDetails = billFeeDetailMap.get(bill.getId());
            deliverBillInfo.setBillId(bill.getId())
                    .setName(TxnCommonUtils.buildDeliverBillName(deliverInfo))
                    .setTotalAmount(bill.getTotalAmount())
                    .setSettledAmount(bill.getSettledAmount())
                    .setUnsettledAmount(unsettledAmount.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : unsettledAmount)
                    .setCreateTime(bill.getCreateTime())
                    .setFeeInfos(feeDetails.stream().map(fee -> new DeliverDetailInfoResp.DeliverFeeInfo()
                            .setFeeId(fee.getId())
                            .setFeeAmount(fee.getFeeAmount().toPlainString())
                            .setFeeName(fee.getFeeName())
                            .setRemark(fee.getRemark())
                    ).collect(Collectors.toList()));
            return deliverBillInfo;
        }).collect(Collectors.toList());
        resp.setSkuInfoList(delSkus);
        resp.setBillInfos(deliverBillInfos);
        return resp;
    }

    @Override
    public void reverseDeliver(Long deliverId) {
        List<TxnSkuDetail> txnSkuDetails = txnSkuDetailService.lambdaQuery()
                .eq(TxnSkuDetail::getDeliverId, deliverId).list();
        txnSkuDetailService.lambdaUpdate()
                .set(TxnSkuDetail::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey())
                .in(TxnSkuDetail::getId, txnSkuDetails.stream().map(TxnSkuDetail::getId).collect(Collectors.toList()))
                .update();
        deliverBillInfoService.lambdaUpdate()
                .eq(DeliverBillInfo::getDeliverId, deliverId)
                .set(DeliverBillInfo::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey())
                .update();
        handleDeliverBillDelete(deliverId, null);
        List<Triple<Long, Long, BigDecimal>> orderSkuDeleteInfos = txnSkuDetails.stream().map(txn -> Triple.of(txn.getOrderId(), txn.getSkuId(), BigDecimal.ZERO.subtract(txn.getDeliveredCount()))).collect(Collectors.toList());
        DeliverInfo deliverInfo = deliverInfoService.getOneById(deliverId);
        saveOrderSkuInfo(deliverInfo, orderSkuDeleteInfos);
        //删除操作
        deliverInfoService.lambdaUpdate()
                .eq(DeliverInfo::getId, deliverId)
                .set(DeliverInfo::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey())
                .set(DeliverInfo::getTagInfo, TxnCommonUtils.getTagInfo(null, new TagInfo(TagInfoEnum.DELIVER_DELETED), Boolean.FALSE))
                .update();
    }

    @Override
    public void stickyOnTop(Long deliverId, Integer type) {
        txnOperateInfoService.saveTopTicket(LyncsOdsConstant.TxnType.DELIVER, deliverId, type);
    }

    @Override
    public DeliverSettleLogResp getDeliverSettleLog(Long deliverId, Long billId) {
        DeliverInfo deliverInfo = deliverInfoService.getOneById(deliverId);
        DeliverSettleLogResp deliverSettleLogResp = new DeliverSettleLogResp();
        List<SettlementBillInfo> settlementBillInfos = settlementBillInfoService.lambdaQuery()
                .eq(SettlementBillInfo::getDeliverId, deliverId)
                .eq(Objects.nonNull(billId), SettlementBillInfo::getDeliverBillId, billId)
                .ne(SettlementBillInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey())
                .list();
        if (Objects.nonNull(billId)) {
            DeliverBillInfo deliverBillInfo = deliverBillInfoService.lambdaQuery()
                    .eq(DeliverBillInfo::getId, billId)
                    .ne(DeliverBillInfo::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey())
                    .one();
            List<TxnFeeDetail> txnFeeDetails = txnFeeDetailService.lambdaQuery().eq(TxnFeeDetail::getBillId, billId).list();
            DeliverSettleLogResp.BillInfo billInfo = new DeliverSettleLogResp.BillInfo()
                    .setStatus(deliverBillInfo.getStatus())
                    .setName(TxnCommonUtils.buildDeliverBillName(deliverInfo))
                    .setTotalAmount(deliverBillInfo.getTotalAmount())
                    .setSettledAmount(deliverBillInfo.getSettledAmount())
                    .setUnsettledAmount(deliverBillInfo.getTotalAmount().subtract(deliverBillInfo.getSettledAmount()))
                    .setCurrency(deliverBillInfo.getCurrency())
                    .setFeeInfos(txnFeeDetails.stream().map(fee -> new DeliverSettleLogResp.Fee().setRemark(fee.getRemark()).setFeeName(fee.getFeeName()).setFeeAmount(fee.getFeeAmount())).collect(Collectors.toList()));
            deliverSettleLogResp.setBillInfo(billInfo);
        }
        if (CollectionUtil.isEmpty(settlementBillInfos)) {
            return deliverSettleLogResp;
        }
        Map<Long, Map<Long, SettlementBillInfo>> settlementBillInfoMap = settlementBillInfos.stream().collect(Collectors.groupingBy(SettlementBillInfo::getSettlementId, Collectors.toMap(SettlementBillInfo::getDeliverBillId, o -> o)));
        List<SettlementInfo> settlementInfos = settlementInfoService.lambdaQuery()
                .in(SettlementInfo::getId, settlementBillInfoMap.keySet())
                .ne(SettlementInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey())
                .list();
        Map<Long, CompanyShortInfoResp> companyShortInfoRespMap = companyInfoService.getTxnCompanyRespInfos(settlementInfos);
        deliverSettleLogResp.setSettlementInfos(settlementInfos.stream().map(stm -> {
            Map<Long, SettlementBillInfo> thisBillInfoMap = settlementBillInfoMap.get(stm.getId());
            BigDecimal thisTotalAmount = thisBillInfoMap.values().stream().map(SettlementBillInfo::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            //结算历史统一取买方企业信息
            SettlementShortInfoResp settlementShortInfoResp = new SettlementShortInfoResp()
                    .setSettleTime(stm.getStartDate())
                    .setCompanyInfo(companyShortInfoRespMap.get(stm.getBuyerId()))
                    .setSettleAmount(thisTotalAmount)
                    .setSettlementId(stm.getId())
                    .setSettlementName(stm.getSettlementName())
                    .setDeliverId(deliverId)
                    .setDeliverName(deliverInfo.getDeliverName());
            if (Objects.nonNull(billId) && MapUtils.isNotEmpty(thisBillInfoMap) && thisBillInfoMap.containsKey(billId)) {
                settlementShortInfoResp.setTagInfos(JSONArray.parseArray(thisBillInfoMap.get(billId).getTagInfo(), TagInfo.class));
            }
            return settlementShortInfoResp;
        }).collect(Collectors.toList()));
        return deliverSettleLogResp;
    }

    @Override
    public CommonPage<TxnEditLogResp> getDeliverEditLog(Long deliverId, Integer page, Integer pageSize) {
        return txnEditLogService.getEditLog(LyncsOdsConstant.TxnType.DELIVER.getKey(), deliverId, page, pageSize);
    }

    @Override
    public CommonPage<UndeliveredOrderSkuResp> listUndeliveredOrder(Long sellerId, Long buyerId, String currency, Long orderId, Integer page, Integer pageSize) {
        List<Integer> undeliveredOrderStatus = List.of(LyncsOdsConstant.OrderStatus.PARTIAL_DELIVERY.getKey(), LyncsOdsConstant.OrderStatus.INIT.getKey());
        LambdaQueryChainWrapper<OrderInfo> wrapper = orderInfoService.lambdaQuery()
                .eq(OrderInfo::getSellerId, sellerId)
                .eq(OrderInfo::getBuyerId, buyerId)
                .eq(OrderInfo::getCurrency, currency)
                .in(OrderInfo::getStatus, undeliveredOrderStatus);
        CommonPage<UndeliveredOrderSkuResp> commonPage = PageUtil.count(wrapper, page, pageSize);
        if (commonPage.getTotal() == 0) {
            return commonPage;
        }
        List<OrderInfo> orderInfos = wrapper.last(PageUtil.getLastSql(page, pageSize, "id", orderId)).list();

        List<Long> orderIds = orderInfos.stream().map(OrderInfo::getId).collect(Collectors.toList());
        List<TxnSkuDetail> txnSkuDetails = txnSkuDetailService.lambdaQuery()
                .isNull(TxnSkuDetail::getDeliverId)
                .in(TxnSkuDetail::getOrderId, orderIds)
                .ne(TxnSkuDetail::getStatus, LyncsOdsConstant.TxnSkuStatus.DELETED.getKey())
                .list();
        Map<Long, List<TxnSkuDetail>> orderSkuMap = txnSkuDetails.stream().collect(Collectors.groupingBy(TxnSkuDetail::getOrderId));

        List<Long> skuIds = txnSkuDetails.stream().map(TxnSkuDetail::getSkuId).distinct().collect(Collectors.toList());
        List<SkuInfo> skuInfos = skuInfoService.lambdaQuery().in(SkuInfo::getId, skuIds).list();
        List<SkuDetail> skuDetails = skuDetailService.lambdaQuery().in(SkuDetail::getSkuId, skuIds).list();
        Map<Long, Map<String, String>> skuAttrMap = skuInfoService.getSkuAttrs(skuDetails);
        Map<Long, SkuInfo> skuInfoMap = skuInfos.stream().collect(Collectors.toMap(SkuInfo::getId, o -> o));
        Function<OrderInfo, UndeliveredOrderSkuResp> func = (info) -> {
            List<TxnSkuDetail> thisOrderSkuList = orderSkuMap.get(info.getId());
            BigDecimal totalAmount = thisOrderSkuList.stream().map(TxnSkuDetail::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            return new UndeliveredOrderSkuResp()
                    .setSelected(info.getId().equals(orderId))
                    .setOrderId(info.getId())
                    .setOrderName(info.getOrderName())
                    .setStatus(info.getStatus())
                    .setCategoryCount(info.getCategoryCount())
                    .setTotalAmount(totalAmount)
                    .setCreateTime(info.getCreateTime())
                    .setSkuInfos(thisOrderSkuList.stream().filter(txn -> skuInfoMap.containsKey(txn.getSkuId())).map(txn -> {
                        SkuInfo skuInfo = skuInfoMap.get(txn.getSkuId());
                        return new UndeliveredOrderSkuResp.OrderSkuInfo()
                                .setSkuId(skuInfo.getId())
                                .setName(skuInfo.getName())
                                .setInnerCode(skuInfo.getNo())
                                .setUnit(skuInfo.getUnit())
                                .setAmount(txn.getAmount())
                                .setImgUrl(skuInfo.getImgUrl())
                                .setTotalCount(txn.getTotalCount())
                                .setDeliveredCount(txn.getDeliveredCount())
                                .setUndeliveredCount(txn.getTotalCount().subtract(txn.getDeliveredCount()))
                                .setSkuAttrs(skuAttrMap.get(skuInfo.getId()));
                    }).collect(Collectors.toList()));
        };
        return PageUtil.result(orderInfos, func, commonPage);
    }

    @Override
    public DeliverSkuLogResp getSkuDeliverLog(Long deliverId, Long skuId) {
        DeliverSkuLogResp deliverLogResp = new DeliverSkuLogResp();
        List<TxnSkuDetail> txnSkuDetails = txnSkuDetailService.lambdaQuery()
                .eq(TxnSkuDetail::getDeliverId, deliverId)
                //有sku时查询该sku在订单交付
                .eq(Objects.nonNull(skuId), TxnSkuDetail::getSkuId, skuId)
                //无sku时查询sku在所有历史订单交付
                .isNotNull(Objects.isNull(skuId), TxnSkuDetail::getOrderId)
                .ne(TxnSkuDetail::getStatus, LyncsOdsConstant.TxnSkuStatus.DELETED.getKey())
                .ne(TxnSkuDetail::getStatus, LyncsOdsConstant.TxnSkuStatus.DELETED.getKey())
                .list();
        if (CollectionUtil.isEmpty(txnSkuDetails)) {
            return deliverLogResp;
        }
        Map<Long, String> orderNameMap = new HashMap<>();
        List<Long> orderIds = txnSkuDetails.stream().map(TxnSkuDetail::getOrderId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(orderIds)) {
            List<OrderInfo> orderInfos = orderInfoService.listByIds(orderIds);
            orderNameMap = orderInfos.stream().collect(Collectors.toMap(OrderInfo::getId, OrderInfo::getOrderName));
        }

        Map<Long, String> finalOrderNameMap = orderNameMap;
        DeliverSkuLogResp.SkuInfo skuRespInfo = new DeliverSkuLogResp.SkuInfo();
        //查询单个sku时才需要skuInfo
        if (Objects.nonNull(skuId)) {
            TxnSkuDetail first = txnSkuDetails.get(0);
            skuRespInfo.setDeliveredCount(first.getDeliveredCount())
                    .setOrderId(first.getOrderId())
                    .setOrderName(finalOrderNameMap.get(first.getOrderId()));
            SkuInfo skuInfo = skuInfoService.lambdaQuery().eq(SkuInfo::getId, skuId).one();
            List<SkuDetail> skuDetails = skuDetailService.lambdaQuery().eq(SkuDetail::getSkuId, skuId).list();
            BeanUtils.copyProperties(skuInfo, skuRespInfo);
            skuRespInfo.setSkuId(skuId)
                    .setInnerCode(skuInfo.getNo())
                    .setSkuAttrs(skuInfoService.getSkuAttrs(skuDetails).get(skuId));
            deliverLogResp.setSkuInfo(skuRespInfo);
        }
        DeliverInfo deliverInfo = deliverInfoService.getOneById(deliverId);
        txnSkuDetails = txnSkuDetails.stream().filter(txn -> txn.getOrderId() != null).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(txnSkuDetails)) {
            return deliverLogResp;
        }
        Map<Long, List<TxnSkuDetail>> deliverSkuMap = txnSkuDetails.stream().collect(Collectors.groupingBy(TxnSkuDetail::getOrderId));

        //该交付单sku关联订单
        Map<Long, CompanyShortInfoResp> txnCompanyInfoMap = TxnCommonUtils.buildTxnCompanyInfo((list) -> companyInfoService.getTxnCompanyRespInfos(list), deliverInfo);
        return deliverLogResp
                //交付历史统一取卖方企业信息
                .setCompanyInfo(txnCompanyInfoMap.get(deliverInfo.getSellerId()))
                .setDeliverTime(deliverInfo.getStartDate())
                .setOrderCount(deliverSkuMap.entrySet().size())
                .setOrderInfos(deliverSkuMap.entrySet().stream().map(entry -> {
                    Long orderId = entry.getKey();
                    List<TxnSkuDetail> thisOrderSkuDetails = entry.getValue();
                    return new DeliverSkuLogResp.OrderDeliverInfo()
                            .setOrderId(orderId)
                            .setOrderName(finalOrderNameMap.get(orderId))
                            .setSkuCount(thisOrderSkuDetails.size())
                            .setDeliverAmount(thisOrderSkuDetails.stream().map(TxnSkuDetail::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add))
                            .setTagInfos(JSONArray.parseArray(thisOrderSkuDetails.get(0).getTagInfo(), TagInfo.class));
                }).collect(Collectors.toList()));
    }

    @Override
    public DeliverLogResp getDeliverLog(Long deliverId) {
        DeliverLogResp deliverLogResp = new DeliverLogResp();
        DeliverSettleLogResp deliverSettleLogResp = this.getDeliverSettleLog(deliverId, null);
        DeliverSkuLogResp deliverSkuLogResp = this.getSkuDeliverLog(deliverId, null);
        deliverLogResp.setSettlementInfos(deliverSettleLogResp.getSettlementInfos())
                .setDeliverSkuInfos(deliverSkuLogResp);
        return deliverLogResp;
    }

    private void handleSettlementInfo(DeliverInfo deliverInfo) {
        List<Integer> influencedStatus = List.of(LyncsOdsConstant.DeliverStatus.PARTIAL_SETTLEMENT.getKey(), LyncsOdsConstant.DeliverStatus.SETTLED.getKey());
        if (deliverInfo == null || !influencedStatus.contains(deliverInfo.getStatus())) {
            return;
        }
        List<DeliverBillInfo> deliverBillInfos = deliverBillInfoService.lambdaQuery()
                .eq(DeliverBillInfo::getDeliverId, deliverInfo.getId())
                .in(DeliverBillInfo::getStatus, influencedStatus)
                .list();
        if (CollectionUtils.isEmpty(deliverBillInfos)) {
            return;
        }
        TagInfo tagInfo = new TagInfo(TagInfoEnum.SKU_OVER_DELIVERED);
        List<DeliverBillInfo> deliverBillUpdateList = new ArrayList<>();
        Map<Long, Boolean> settlementBillTagMap = new HashMap<>();
        deliverBillInfos.forEach(bill -> {
            //当前账款已结算金额
            BigDecimal settledAmount = bill.getSettledAmount();
            BigDecimal totalAmount = bill.getTotalAmount();
            //未结算校验,用已结算金额 或者 用状态判断
            if (BigDecimal.ZERO.equals(settledAmount) ||
                    (totalAmount.compareTo(settledAmount) > 0 && LyncsOdsConstant.DeliverStatus.PARTIAL_SETTLEMENT.getKey().equals(deliverInfo.getStatus())) ||
                    (settledAmount.equals(totalAmount) && LyncsOdsConstant.DeliverStatus.SETTLED.getKey().equals(deliverInfo.getStatus()))) {
                return;
            }
            LyncsOdsConstant.DeliverStatus deliverBillStatus = settledAmount.compareTo(totalAmount) < 0 ? LyncsOdsConstant.DeliverStatus.PARTIAL_SETTLEMENT : LyncsOdsConstant.DeliverStatus.SETTLED;
            DeliverBillInfo deliverBillInfo = new DeliverBillInfo().setId(bill.getId()).setStatus(deliverBillStatus.getKey());
            //当前交付单的总结算金额改大了（改完后应为部分结算），且当前账款状态为部分结算
            if (totalAmount.compareTo(settledAmount) < 0 && LyncsOdsConstant.DeliverStatus.PARTIAL_SETTLEMENT.getKey().equals(deliverInfo.getStatus())) {
                settlementBillTagMap.put(bill.getId(), Boolean.FALSE);
                deliverBillInfo.setTagInfo(TxnCommonUtils.getTagInfo(bill.getTagInfo(), tagInfo, Boolean.FALSE));
            }
            //当前交付单的总结算金额改小了（改完后应为已结算），且当前账款状态为已结算
            if (LyncsOdsConstant.DeliverStatus.SETTLED.getKey().equals(deliverInfo.getStatus()) && settledAmount.compareTo(totalAmount) > 0) {
                settlementBillTagMap.put(bill.getId(), Boolean.FALSE);
                deliverBillInfo.setTagInfo(TxnCommonUtils.getTagInfo(bill.getTagInfo(), tagInfo, Boolean.FALSE));
            }
            deliverBillUpdateList.add(deliverBillInfo);
        });
        //更新结算账款状态
        if (CollectionUtils.isNotEmpty(deliverBillUpdateList)) {
            deliverBillInfoService.updateBatchById(deliverBillUpdateList);
        }
        if (MapUtils.isNotEmpty(settlementBillTagMap)) {
            List<SettlementBillInfo> settlementBillList = settlementBillInfoService.lambdaQuery()
                    .eq(SettlementBillInfo::getDeliverId, deliverInfo.getId())
                    .in(SettlementBillInfo::getDeliverBillId, settlementBillTagMap.keySet())
                    .ne(SettlementBillInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey())
                    .list();
            List<SettlementBillInfo> settlementBillUpdateList = settlementBillList.stream().map(bill -> new SettlementBillInfo().setId(bill.getId()).setTagInfo(TxnCommonUtils.getTagInfo(bill.getTagInfo(), tagInfo, settlementBillTagMap.get(bill.getDeliverBillId())))).collect(Collectors.toList());
            settlementBillInfoService.updateBatchById(settlementBillUpdateList);
        }
    }

    private void handleDeliverBillDelete(@NotNull Long deliverId, Set<Long> billIds) {
        TagInfoEnum tagInfoEnum = CollectionUtils.isNotEmpty(billIds) ? TagInfoEnum.DELIVER_Bill_DELETED : TagInfoEnum.DELIVER_DELETED;
        TagInfo tagInfo = new TagInfo(tagInfoEnum);
        List<SettlementBillInfo> settlementBillList = settlementBillInfoService.lambdaQuery()
                .eq(SettlementBillInfo::getDeliverId, deliverId)
                .in(CollectionUtils.isNotEmpty(billIds), SettlementBillInfo::getDeliverBillId, billIds)
                .ne(SettlementBillInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey())
                .list();
        List<SettlementBillInfo> settlementBillUpdateList = settlementBillList.stream().map(bill -> new SettlementBillInfo().setId(bill.getId()).setTagInfo(TxnCommonUtils.getTagInfo(bill.getTagInfo(), tagInfo, Boolean.FALSE))).collect(Collectors.toList());
        settlementBillInfoService.updateBatchById(settlementBillUpdateList);
    }

    @Deprecated
    private void handleDeliverSkuUpdate(List<Long> orderIds) {
        if (CollectionUtils.isEmpty(orderIds)) {
            return;
        }
        List<TxnSkuDetail> txnSkuDetails = txnSkuDetailService.lambdaQuery().in(TxnSkuDetail::getOrderId, orderIds).ne(TxnSkuDetail::getStatus, LyncsOdsConstant.TxnSkuStatus.DELETED.getKey()).list();
        Map<Boolean, List<TxnSkuDetail>> txnSkuDetailMap = txnSkuDetails.stream().collect(Collectors.groupingBy(i -> i.getDeliverId() == null));
        List<TxnSkuDetail> orderSkuDetails = txnSkuDetailMap.get(Boolean.TRUE);
        List<TxnSkuDetail> orderDeliverSkuDetails = txnSkuDetailMap.get(Boolean.FALSE);
        if (CollectionUtils.isEmpty(orderSkuDetails) || CollectionUtils.isEmpty(orderDeliverSkuDetails)) {
            return;
        }
        List<TxnSkuDetail> updateOrderSkus = new ArrayList<>();
        Map<String, TxnSkuDetail> orderSkuDetailMap = orderSkuDetails.stream().collect(Collectors.toMap(txn -> TxnCommonUtils.buildLong2StringKey(txn.getOrderId(), txn.getSkuId()), o -> o));
        Map<String, List<TxnSkuDetail>> deliveredSkuMap = orderDeliverSkuDetails.stream().collect(Collectors.groupingBy(txn -> TxnCommonUtils.buildLong2StringKey(txn.getOrderId(), txn.getSkuId())));
        orderSkuDetailMap.forEach((key, txn) -> {
            List<TxnSkuDetail> deliveredSkus = deliveredSkuMap.get(key);
            BigDecimal totalCount = txn.getTotalCount();
            BigDecimal deliveredCount = deliveredSkus.stream().map(TxnSkuDetail::getDeliveredCount).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (deliveredCount.compareTo(totalCount) > 0) {
                throw new ApiException("请勿超量交付，" + txn.getOrderId() + "@" + txn.getSkuId() + "的待交付量为" + (txn.getTotalCount().subtract(txn.getDeliveredCount())) + "，小于当前填写交付量。");
            }
            Integer status = deliveredCount.compareTo(BigDecimal.ZERO) == 0 ? LyncsOdsConstant.TxnSkuStatus.INIT.getKey() : deliveredCount.compareTo(totalCount) < 0 ? LyncsOdsConstant.TxnSkuStatus.PARTIAL_DELIVERY.getKey() : LyncsOdsConstant.TxnSkuStatus.DELIVERED.getKey();
            updateOrderSkus.add(
                    new TxnSkuDetail().setId(txn.getId())
                            .setDeliveredCount(deliveredCount)
                            .setStatus(status)
                            .setLastUpdater(RequestHolder.getUserId())
                            .setUpdateTime(RequestHolder.getRequestDateTime())
            );
        });
        txnSkuDetailService.updateBatchById(updateOrderSkus);
        orderInfoService.updateOrderStatus(orderIds);
    }
}
